package com.owc.common.encryption;

import com.owc.common.configuration.OwcConfig;
import com.owc.common.converter.IDecodeAdvice;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

public class XXTEADecode implements IDecodeAdvice<byte[]> {
    @Override
    public String decode(byte[] encryption) {
        return XXTEA.decryptToString(encryption, OwcConfig.encryKey);
    }

    public static void main(String[] args) {

        String key = "6t3ZUVyGiQK2hUd1eavo1Lp6%cTNvIvgnRV*wx6MgLi&snYgk95DE49cf^IJSI8";
        String json = "{\"phone\":\"18224449005\",\"password\":\"chen19960119\",\"confirmPassword\":\"chen19960119\",\"authCode\":\"294842\",\"type\":2}";

        String str1 = "JTdCJTIyYnV5QW1vdW50JTIyJTNBJTIyMTIwJTIyJTJDJTIycGhvbmUlMjIlM0ElMjIxODIyNDQ0OTAwNSUyMiUyQyUyMnByb2R1Y3RJZCUyMiUzQTglN0Q=";

//        String str = "怒福ID舒服";
//
//        String encode = new String(Base64.getEncoder().encode(str.getBytes()), StandardCharsets.UTF_8);
//
//        System.out.println(encode);
        Base64.Decoder decoder = Base64.getDecoder();
        System.out.println(URLDecoder.decode(new String(decoder.decode(str1.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)));
        System.out.println("1111::=="+new String(decoder.decode("PyeKo3oc9gLHBNjgXMB0Pw\\u003d\\u003d\\n")));
//        byte[] data = XXTEA.encrypt(json.getBytes(),key);
//        System.out.println("加密数：" + Arrays.toString(data));
//        System.out.println("解密数据：" + XXTEA.decryptToString(data,key));
    }

    public static class XXTEA{
        private static final int DELTA = 0x9E3779B9;

        private static int MX(int sum, int y, int z, int p, int e, int[] k) {
            return (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        }

        private XXTEA() {}

        public static byte[] encrypt(byte[] data, byte[] key) {
            if (data.length == 0) {
                return data;
            }
            return toByteArray(
                    encrypt(toIntArray(data, true), toIntArray(fixKey(key), false)), false);
        }
        public static byte[] encrypt(String data, byte[] key) {
            return encrypt(data.getBytes(StandardCharsets.UTF_8), key);
        }
        public static byte[] encrypt(byte[] data, String key) {
            return encrypt(data, key.getBytes(StandardCharsets.UTF_8));
        }
        public static String encrypt(String data, String key) {
            return new String(encrypt(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8)));
        }

        public static byte[] decrypt(byte[] data, byte[] key) {
            if (data.length == 0) {
                return data;
            }
            return toByteArray(
                    decrypt(toIntArray(data, false), toIntArray(fixKey(key), false)), true);
        }
        public static byte[] decrypt(byte[] data, String key) {
            return decrypt(data, key.getBytes(StandardCharsets.UTF_8));
        }

        public static String decryptToString(byte[] data, String key) {
            byte[] bytes = decrypt(data, key);
            if (bytes == null) {
                return "error";
            }
            return new String(bytes, StandardCharsets.UTF_8);
        }

        private static int[] encrypt(int[] v, int[] k) {
            int n = v.length - 1;

            if (n < 1) {
                return v;
            }
            int p, q = 6 + 52 / (n + 1);
            int z = v[n], y, sum = 0, e;

            while (q-- > 0) {
                sum = sum + DELTA;
                e = sum >>> 2 & 3;
                for (p = 0; p < n; p++) {
                    y = v[p + 1];
                    z = v[p] += MX(sum, y, z, p, e, k);
                }
                y = v[0];
                z = v[n] += MX(sum, y, z, p, e, k);
            }
            return v;
        }

        private static int[] decrypt(int[] v, int[] k) {
            int n = v.length - 1;

            if (n < 1) {
                return v;
            }
            int p, q = 6 + 52 / (n + 1);
            int z, y = v[0], sum = q * DELTA, e;

            while (sum != 0) {
                e = sum >>> 2 & 3;
                for (p = n; p > 0; p--) {
                    z = v[p - 1];
                    y = v[p] -= MX(sum, y, z, p, e, k);
                }
                z = v[n];
                y = v[0] -= MX(sum, y, z, p, e, k);
                sum = sum - DELTA;
            }
            return v;
        }

        private static byte[] fixKey(byte[] key) {
            if (key.length == 16) {
                return key;
            }
            byte[] fixedkey = new byte[16];
            if (key.length < 16) {
                System.arraycopy(key, 0, fixedkey, 0, key.length);
            }
            else {
                System.arraycopy(key, 0, fixedkey, 0, 16);
            }
            return fixedkey;
        }

        private static int[] toIntArray(byte[] data, boolean includeLength) {
            int n = (((data.length & 3) == 0)
                    ? (data.length >>> 2)
                    : ((data.length >>> 2) + 1));
            int[] result;

            if (includeLength) {
                result = new int[n + 1];
                result[n] = data.length;
            }
            else {
                result = new int[n];
            }
            n = data.length;
            for (int i = 0; i < n; ++i) {
                result[i >>> 2] |= (0x000000ff & data[i]) << ((i & 3) << 3);
            }
            return result;
        }

        private static byte[] toByteArray(int[] data, boolean includeLength) {
            int n = data.length << 2;

            if (includeLength) {
                int m = data[data.length - 1];
                n -= 4;
                if ((m < n - 3) || (m > n)) {
                    return null;
                }
                n = m;
            }
            byte[] result = new byte[n];

            for (int i = 0; i < n; ++i) {
                result[i] = (byte) (data[i >>> 2] >>> ((i & 3) << 3));
            }
            return result;
        }
    }

}

